package com.lizhenhua.fmmall.service.serviceImpl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lizhenhua.fmmall.entity.*;
import com.lizhenhua.fmmall.mapper.ProductImgMapper;
import com.lizhenhua.fmmall.mapper.ProductMapper;
import com.lizhenhua.fmmall.mapper.ProductParamsMapper;
import com.lizhenhua.fmmall.mapper.ProductSkuMapper;
import com.lizhenhua.fmmall.service.ProductService;
import com.lizhenhua.fmmall.utils.PageHelper;
import com.lizhenhua.fmmall.vo.ResStatus;
import com.lizhenhua.fmmall.vo.ResultVo;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.*;

@Service
public class ProductServiceImpl implements ProductService {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // 查询商品信息 和他的图片
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductImgMapper productImgMapper;
    @Autowired
    private ProductSkuMapper productSkuMapper;
    @Autowired
    private ProductParamsMapper productParamsMapper;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public ResultVo selectProductAndImg() {

        List<ProductVo> productVos = productMapper.selectAllProducts();

        return new ResultVo(ResStatus.OK, "success", productVos);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public ResultVo getProductBasicInfo(String productId) {
        try {
            // 根据商品id查询redis 第一次查的时候为空
            //2. 判断  如果redis查询到信息 则直接返回给控制器
            String productsInfo = (String) stringRedisTemplate.boundHashOps("products").get(productId);
            if (productsInfo != null) {
                // 把字符串转换为对象
                Product product = new ObjectMapper().readValue(productsInfo, Product.class);


                // 得到productImgs数据
                String imgstr = (String) stringRedisTemplate.boundHashOps("productImgs").get(productId);

                // 把字符串 转换为对象
                JavaType javaType1 = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductImg.class);
                List<ProductImg> productImgs = objectMapper.readValue(imgstr, javaType1);


                //得到productSku 数据
                String skustr = (String) stringRedisTemplate.boundHashOps("productSkus").get(productId);
                JavaType javaType2 = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductSku.class);
                List<ProductSku> productSkus = objectMapper.readValue(skustr, javaType2);


                HashMap<String, Object> basicInfo = new HashMap<>();
                basicInfo.put("product", product);
                basicInfo.put("productImgs", productImgs);
                basicInfo.put("productSkus", productSkus);
                return new ResultVo(ResStatus.OK, "success", basicInfo);
            } else {
                // 如果redis中没查询到数据则

                //1. 查询商品信息

                Example example = new Example(Product.class);
                Example.Criteria criteria = example.createCriteria();
                //"productId" 是你mapper 文件中设置的 名字
                criteria.andEqualTo("productId", productId);
                // 状态为1 表示上架商品
                criteria.andEqualTo("productStatus", 1);
                List<Product> products = productMapper.selectByExample(example);
                if (products.size() > 0) {
                    // 将从数据库查询的数据写入redis
                    Product p = products.get(0);
                    String s = objectMapper.writeValueAsString(p);
                    stringRedisTemplate.boundHashOps("products").put(productId, s);


                    Example exampleImg = new Example(ProductImg.class);
                    Example.Criteria criteriaImg = exampleImg.createCriteria();
                    criteriaImg.andEqualTo("itemId", productId);
                    List<ProductImg> productImgs = productImgMapper.selectByExample(exampleImg);
                    // 商品id作为key 集合作为value
                    stringRedisTemplate.boundHashOps("productImgs").put(productId, objectMapper.writeValueAsString(productImgs));

                    // 查询商品套餐
                    Example exampleSku = new Example(ProductSku.class);
                    Example.Criteria criteriaSku = exampleSku.createCriteria();
                    criteriaSku.andEqualTo("productId", productId);
                    criteriaSku.andEqualTo("status", 1);
                    List<ProductSku> productSkus = productSkuMapper.selectByExample(exampleSku);
                    // 套餐信息设置到redis里面
                    stringRedisTemplate.boundHashOps("productSkus").put(productId, objectMapper.writeValueAsString(productSkus));

                    HashMap<String, Object> basicInfo = new HashMap<>();
                    basicInfo.put("product", products.get(0));
                    basicInfo.put("productImgs", productImgs);
                    basicInfo.put("productSkus", productSkus);

                    return new ResultVo(ResStatus.OK, "success", basicInfo);


                } else {
                    return new ResultVo(ResStatus.NO, "fail", null);
                }

//              if (products.size() > 0) {
//                  // 查询商品图片
//                  Example exampleImg = new Example(ProductImg.class);
//                  Example.Criteria criteriaImg = exampleImg.createCriteria();
//                  criteriaImg.andEqualTo("itemId", productId);
//                  List<ProductImg> productImgs = productImgMapper.selectByExample(exampleImg);
//
//                  // 查询商品套餐
//                  Example exampleSku = new Example(ProductSku.class);
//                  Example.Criteria criteriaSku = exampleSku.createCriteria();
//                  criteriaSku.andEqualTo("productId", productId);
//                  criteriaSku.andEqualTo("status", 1);
//                  List<ProductSku> productSkus = productSkuMapper.selectByExample(exampleSku);
//
//                  HashMap<String, Object> basicInfo = new HashMap<>();
//                  basicInfo.put("product", products.get(0));
//                  basicInfo.put("productImgs", productImgs);
//                  basicInfo.put("productSkus", productSkus);
//
//
//                  return new ResultVo(ResStatus.OK, "获取成功", basicInfo);
//              } else {
//
//                  return new ResultVo(ResStatus.NO, "没有此商品", null);
//              }
            }

        } catch (Exception e) {

        }
        return new ResultVo(ResStatus.NO, "fail", null);
    }

    @Override
    public ResultVo getProductById(String productId) {
        Example example = new Example(ProductParams.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("productId", productId);
        List<ProductParams> productParams = productParamsMapper.selectByExample(example);


        if (productParams.size() < 1) {
            return new ResultVo(ResStatus.NO, "此产品可能为三无产品", null);
        } else {
            return new ResultVo(ResStatus.OK, "success", productParams);
        }
    }

    @Override
    public ResultVo getProductByCategoryId(int categoryId, int pageNum, int limit) {

        // 1. 查询分页数据
        int start = (pageNum - 1) * limit;

        List<ProductVo> productVos = productMapper.selectProductByCategoryId(categoryId, start, limit);

        //2.查询当前类别商品下的总记录数 count
        Example example = new Example(Product.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("categoryId", categoryId);
        List<Product> products = productMapper.selectByExample(example);
        //3. 计算 总记录数
        int count = products.size();
        // .计算总页数
        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
        // 4. 封装数据

        // 因为是分页查询 所以data 里面应该是个 PageHelper对象
        //count 总记录数 pageCount 总页数 productVos 每页的数据
        return new ResultVo(ResStatus.OK, "success", new PageHelper<ProductVo>(count, pageCount, productVos));
    }

    @Override
    public ResultVo brandList(int categoryId) {
        // 查询到的品牌集合
        List<String> strings = productMapper.selectBrandByCategoryId(categoryId);


        return new ResultVo(ResStatus.OK, "success", strings);
    }

    @Override
    public ResultVo searchProduct(String keyword, int pageNum, int limit) {

        // 分页开始位置
        int start = (pageNum - 1) * limit;

        SearchRequest searchRequest = new SearchRequest("fmmallproductindex");
        // 用来封装查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //查询条件

        searchSourceBuilder.query(QueryBuilders.multiMatchQuery(keyword, "productName", "productSkuName"));
        //分页条件
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(limit);

        //高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //高亮显示的字段
        HighlightBuilder.Field field1 = new HighlightBuilder.Field("productName");
        HighlightBuilder.Field field2 = new HighlightBuilder.Field("productSkuName");
        highlightBuilder.field(field1);
        highlightBuilder.field(field2);
        // 设置显示的颜色
        highlightBuilder.preTags("<label style='color:red'>");
        highlightBuilder.postTags("</label>");
        searchSourceBuilder.highlighter(highlightBuilder);
        // 执行高亮显示
        searchRequest.source(searchSourceBuilder);
        // 执行检索
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHits hits = searchResponse.getHits();//获取命中的数据

        int count =(int)hits.getTotalHits().value; // 得到总记录数
        int pageCount = (int) (count % limit == 0 ? count / limit : count / limit + 1);//获取总页数


        for (SearchHit hit : hits
        ) {
            System.out.println(hit);
        }


        // 从对检索的结果处理 封装成我们需要的List集合
        List<ProductForES> productList = new ArrayList<>();

        Iterator<SearchHit> iterator = hits.iterator();
        while (iterator.hasNext()) {
            // 获取单条数据
            SearchHit searchHit = iterator.next();

            // 把source里面的数据转换为字符串
            String str = searchHit.getSourceAsString();
            // 把字符串转换为对象
            ProductForES product = null;
            try {
                product = objectMapper.readValue(str, ProductForES.class);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            // 高亮显示的字段  searchHit.getHighlightFields()取得高亮字段 是一个map
            HighlightField highlightField = searchHit.getHighlightFields().get("productName");
            HighlightField highlightField2 = searchHit.getHighlightFields().get("productSkuName");
            System.out.println(highlightField);
            if (highlightField != null) {
                // 把数组返回为 字符串 因为 高亮显示的内容在debug模式中 存在highlightField里面的fragments中
                String s = Arrays.toString(highlightField.fragments());
                // 重新给product 字段赋值
                product.setProductName(s);
            }
            if (highlightField2 != null) {
                // 把数组返回为 字符串 因为 高亮显示的内容在debug模式中 存在highlightField里面的fragments中
                String s = Arrays.toString(highlightField.fragments());
                // 重新给product 字段赋值
                product.setProductName(s);
            }


            // 给集合里面添加数据
            productList.add(product);
        }


        return new ResultVo(ResStatus.OK, "success", new PageHelper<ProductForES>(count, pageCount,productList));
    }

    @Override
    public ResultVo searchBrand(String keyword) {
        keyword = "%" + keyword + "%";
        List<String> strings = productMapper.selectBrandByKeyword(keyword);
        return new ResultVo(ResStatus.OK, "success", strings);
    }

}
